package com.ljph.jfinal.service;

import com.jfinal.core.Controller;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Page;
import com.ljph.jfinal.dto.ApiResult;
import com.ljph.jfinal.dto.PageWrapper;
import com.ljph.kit.CommonKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * 构建分页查询的服务
 * Created by yuzhou on 16/12/25.
 */
public class PageService<T extends Model> {


  public enum FilterType {
    EQUAL,
    FUZZY_MATCH,
    GREAT_THAN,
    LESS_THAN,
    GREAT_THAN_EQUAL,
    LESS_THAN_EQUAL
  }

  private static final Logger _log = LoggerFactory.getLogger(PageService.class);

  /* 查询子句，限定返回结果 */
  protected String selectSql;

  protected StringBuffer tableSql;

  /* 查询过滤条件 */
  protected StringBuffer filterSql;

  public PageService<T> setOrderSql(StringBuffer orderSql) {
    this.orderSql = orderSql;
    return this;
  }

  /* 查询排序条件 */
  protected StringBuffer orderSql;

  /* 查询SQL 预处理语句实参列表 */
  protected List<Object> params;

  protected int pageNumber = 1;

  protected int pageSize = 10;

  public PageService<T> setPageSize(int pageSize) {
    this.pageSize = pageSize;
    return this;
  }

  protected T dao;
  protected Controller controller;

  public boolean isWithUpdateTime() {
    return withUpdateTime;
  }

  public PageService<T> setWithUpdateTime(boolean withUpdateTime) {
    this.withUpdateTime = withUpdateTime;
    return this;
  }

  protected boolean withUpdateTime = true;

  /**
   * 构造函数
   */
  public PageService(T dao, Controller controller) {
    this.dao = dao;
    this.controller = controller;

    selectSql = "select mt.*";
    params = new ArrayList<Object>();
    tableSql = new StringBuffer(" from " + CommonKit.getTableName(dao.getClass()) + " mt");
    filterSql = new StringBuffer(" where 1=1");

    if(withUpdateTime) {
      orderSql = new StringBuffer(" order by mt.updateTime desc");
    } else {
      orderSql = new StringBuffer(" ");
    }
  }

  public PageService<T> leftJoin(String leftJoinSql) {
    tableSql.append(" left join " + leftJoinSql);
    return this;
  }

  public PageService addFilter(String column, Object param) {
    if(param == null || column == null) return this;
    return addFilter(column, param, FilterType.EQUAL);
  }

  public PageService addCustomFilter(String sql, Object ... sqlParams) {
    filterSql.append(sql);

    for(Object param : sqlParams) {
      this.params.add(param);
    }

    return this;
  }

  public PageService addFilter(String column, Object param, FilterType filterType) {

    if(param == null || column == null) return this;

    filterSql.append(" and " + column);
    switch (filterType) {
      case EQUAL:
        filterSql.append(" = ?");
        params.add(param);
        break;
      case FUZZY_MATCH:
        filterSql.append(" like ?");
        params.add("%" + param + "%");
        break;
      case GREAT_THAN:
        filterSql.append(" > ?");
        params.add(param);
        break;
      case GREAT_THAN_EQUAL:
        filterSql.append(" >= ?");
        params.add(param);
        break;
      case LESS_THAN:
        filterSql.append(" < ?");
        params.add(param);
        break;
      case LESS_THAN_EQUAL:
        filterSql.append(" <= ?");
        params.add(param);
        break;
      default:
        break;
    }

    return this;
  }

  /**
   * 获取颁查询结果并封装在dto对象 ApiResult中
   * @return
   */
  public ApiResult paginate(){

    pageNumber = controller.getParaToInt("pn", 1);

    if(withUpdateTime) {
      Long lastTs = controller.getParaToLong("lastTs");

      if (lastTs != null) {
        filterSql.append(" and mt.updateTime <= ?");
        params.add(lastTs);
      } else {
        pageNumber = 1;
      }
    }

    Page page = dao.paginate(pageNumber,
      pageSize,
      selectSql,
      tableSql.toString()
        + filterSql.toString()
        + orderSql.toString(),
      params.toArray());

    ApiResult apiResult = new ApiResult(true);
    // 加载第一页数据时，返回数据加载时间
    if(pageNumber == 1) {
      apiResult.setTs();
    }
    return apiResult.setData(new PageWrapper().setPage(page));
  }


}
